﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;

namespace LowLevelGraphics.Filter
{
    /// <summary>
    /// Deal with brightness, darker or brighter by the intensity of Intensity I
    /// </summary>
    public class BrighterDarker : BaseImageFilter
    {
        protected short m_sValue = 10;

        /// <summary>
        /// Initializes a new instance of the <see cref="BrighterDarker"/> class.
        /// </summary>
        public BrighterDarker()
            : this(10)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="BrighterDarker"/> class.
        /// </summary>
        /// <param name="_sValue">The _s value.</param>
        public BrighterDarker(short _sValue)
        {
            m_sValue = _sValue;
        }

        /// <summary>
        /// Used by cloning
        /// </summary>
        /// <param name="_brighterDarker"></param>
        internal BrighterDarker(BrighterDarker _brighterDarker)
        {
            this.m_sValue = _brighterDarker.m_sValue;
        }

        /// <summary>
        /// Gets or sets the intensity.
        /// </summary>
        /// <value>The intensity.</value>
        public short Intensity
        {
            get { return m_sValue; }
            set { m_sValue = value; }
        }

        /// <summary>
        /// Execute this Filter
        /// A Debug Statement is written if a concrete Filter is called
        /// </summary>
        /// <param name="_bitmap"></param>
        /// <returns></returns>
        public override UnsafeBitmap Execute(UnsafeBitmap _bitmap)
        {
            UnsafeBitmap bitmap = _bitmap;
            int x = 0;
            int y = 0;
            int offset = 0;
            byte rv = 0;
            byte gv = 0;
            byte bv = 0;
            IntPtr ptr = IntPtr.Zero;
            int lineoffs = 0;
            byte[] ar = new byte[256];
            int i = 0;

            for (x = 0; x < 256; x++)
            {
                i = (int)(x + m_sValue);
                if (i < 0) i = 0;
                if (i > 255) i = 255;
                ar[x] = (byte)i;
            }

            BitmapData bmpData = bitmap.BitmapData; //bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
            ptr = bmpData.Scan0;
            offset = 0;
            lineoffs = bitmap.OffsetPointerIncrease; //bmpData.Stride - bitmap.Width * 3;
            int nByteCount = bitmap.BytesPerPixelCount;

            for (y = 0; y < bitmap.Height - 1; y++)
            {
                for (x = 0; x < bitmap.Width - 1; x++)
                {
                    bv = Marshal.ReadByte(ptr, offset);
                    gv = Marshal.ReadByte(ptr, offset + 1);
                    rv = Marshal.ReadByte(ptr, offset + 2);

                    Marshal.WriteByte(ptr, offset, ar[bv]);
                    Marshal.WriteByte(ptr, offset + 1, ar[gv]);
                    Marshal.WriteByte(ptr, offset + 2, ar[rv]);
                    offset += nByteCount;
                }
                offset += lineoffs;
            }
            return _bitmap;
        }

        /// <summary>
        /// This is used to clone a filter, each filter must implement it's own clone functionality
        /// </summary>
        /// <returns></returns>
        public override object Clone()
        {
            return new BrighterDarker(this);
        }
    }
}
